#include <tinx/device.h>
#include <tinx/debug.h>
#include <tinx/fs.h>
#include <tinx/assert.h>
#include <tinx/string.h>
#include <tinx/syscall.h>

#define LOGK(str, args...) DEBUGK(str, ##args)

#define NR_SUPER 64

static super_t super_table[NR_SUPER];

super_t *get_free_super()
{
    for (size_t i = 0; i < NR_SUPER; i++)
    {
        super_t *super = &super_table[i];
        if (super->dev == EOF)
            return super;
    }
    panic("No more super blocks!\n");
}

// 获得超级块
super_t *get_super(dev_t dev)
{
    for (size_t i = 0; i < NR_SUPER; i++)
    {
        super_t *ptr = &super_table[i];
        if (ptr->dev == dev)
        {
            return ptr;
        }
    }
    return NULL;
}

// 读超级块
super_t *read_super(dev_t dev)
{
    super_t *super = get_super(dev);
    if (super)
    {
        super->count++;
        return super;
    }

    super = get_free_super();
    super->dev = dev;

    list_init(&super->inode_list);

    for (size_t i = 1; i < FS_TYPE_NUM; i++)
    {
        super->op = fs_get_op(i);
        if (!super->op)
            continue;
        if (!super->op->read_super)
            continue;
        if (super->op->read_super(dev, super) < 0)
        {
            super->op = NULL;
            continue;
        }
        break;
    }

    if (!super->op)
        return NULL;

    super->count = 1;

    return super;
}

void put_super(super_t *super)
{
    if (!super)
        return;
    super->count--;
    if (super->count)
        return;
    super->op->put_super(super);
    super->dev = EOF;
}

void mount_root()
{
    dev_t dev = device_find(DEV_FLAG_PART, 1);
    super_t *super = read_super(dev);
    if (!super)
    {
        panic("failed to mount rootfs");
    }

    super->imount = super->iroot;
    super->imount->count++;

    device_t *device = device_get(super->dev);

    LOGK("Mount root at %s\n", device->name);
}

// 初始化超级块
void super_init()
{
    for (size_t i = 0; i < NR_SUPER; i++)
    {
        super_t *super = &super_table[i];
        memset(super, 0, sizeof(super_t));
        super->dev = EOF;
    }
    mount_root();
}